home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  32.9 KB  |  1,740 lines

  1. /*
  2.  *
  3.  * glob.c - filename generation
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made.
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk.
  18.  *
  19.  */
  20.  
  21. #include "zsh.h"
  22.  
  23. #include <errno.h>
  24. #include <pwd.h>
  25. #include <grp.h>
  26.  
  27. #define exists(X) (access(X,0) == 0 || readlink(X,NULL,0) == 0)
  28.  
  29. static int mode;        /* != 0 if we are parsing glob patterns */
  30. static int pathpos;        /* position in pathbuf */
  31. static int matchsz;        /* size of matchbuf */
  32. static int matchct;        /* number of matches found */
  33. static char pathbuf[MAXPATHLEN];/* pathname buffer */
  34. static char **matchbuf;        /* array of matches */
  35. static char **matchptr;        /* &matchbuf[matchct] */
  36. static Comp exclude;        /* pattern to exclude */
  37. static char *colonmod;        /* colon modifiers in qualifier list */
  38.  
  39. #ifdef ULTRIX
  40. typedef struct stat *Statptr;    /* This makes the Ultrix compiler happy.  Go figure. */
  41.  
  42. #endif
  43.  
  44. #define TT_DAYS 0
  45. #define TT_HOURS 1
  46. #define TT_MINS 2
  47. #define TT_WEEKS 3
  48. #define TT_MONTHS 4
  49.  
  50. /* max # of qualifiers */
  51.  
  52. struct qual {
  53.     struct qual *next, *or;
  54.     int (*func) DCLPROTO((struct stat *, long));
  55.     long data;
  56.     int sense;
  57.     int amc;
  58.     int range;
  59.     int timef;
  60. };
  61.  
  62. static struct qual *quals;
  63.  
  64. static int qualct, qualorct;
  65. static int range, amc, timef;
  66. static int gf_nullglob, gf_markdirs, gf_noglobdots, gf_listtypes;
  67.  
  68. char *glob_pre, *glob_suf;
  69.  
  70. /* pathname component in filename patterns */
  71.  
  72. struct complist {
  73.     Complist next;
  74.     Comp comp;
  75.     int closure;        /* 1 if this is a (foo/)# */
  76. };
  77. struct comp {
  78.     Comp left, right, next;
  79.     char *str;
  80.     int closure, last;
  81. };
  82.  
  83. void glob(list, np)        /**/
  84. Lklist list;
  85. Lknode *np;
  86. {
  87.     struct qual *qo, *qn, *ql;
  88.     Lknode node = prevnode(*np);
  89.     Lknode next = nextnode(*np);
  90.     int luh = useheap;
  91.     char *str;            /* the pattern */
  92.     int sl;            /* length of the pattern */
  93.     Complist q;            /* pattern after parsing */
  94.     char *ostr = (char *)getdata(*np);    /* the pattern before the parser chops it up */
  95.  
  96.     heapalloc();
  97.     str = dupstring(ostr);
  98.     if (!luh)
  99.     permalloc();
  100.     sl = strlen(str);
  101.     uremnode(list, *np);
  102.     qo = qn = quals = ql = NULL;
  103.     qualct = qualorct = 0;
  104.     colonmod = NULL;
  105.     gf_nullglob = isset(NULLGLOB);
  106.     gf_markdirs = isset(MARKDIRS);
  107.     gf_listtypes = 0;
  108.     gf_noglobdots = unset(GLOBDOTS);
  109.     if (str[sl - 1] == Outpar) {/* check for qualifiers */
  110.     char *s;
  111.     int sense = 0;
  112.     long data = 0;
  113.  
  114. #ifdef ULTRIX
  115.     int (*func) DCLPROTO((Statptr, long));
  116.  
  117. #else
  118.     int (*func) DCLPROTO((struct stat *, long));
  119.  
  120. #endif
  121.  
  122.     for (s = str + sl - 2; s != str; s--)
  123.         if (*s == Bar || *s == Outpar || *s == Inpar)
  124.         break;
  125.     if (*s == Inpar) {
  126.         *s++ = '\0';
  127.         while (*s != Outpar && !colonmod) {
  128. #ifdef ULTRIX
  129.         func = (int (*)DCLPROTO((Statptr, long)))0;
  130. #else
  131.         func = (int (*)DCLPROTO((struct stat *, long)))0;
  132. #endif
  133.         if (idigit(*s)) {
  134.             func = qualflags;
  135.             data = 0;
  136.             while (idigit(*s))
  137.             data = data * 010 + (*s++ - '0');
  138.         } else if (*s == ',' || *s == Comma) {
  139.             s++;
  140.             if (qualct) {
  141.             qn = (struct qual *) hcalloc(sizeof *qn);
  142.             qo->or = qn;
  143.             qo = qn;
  144.             qualorct++;
  145.             qualct = 0;
  146.             ql = NULL;
  147.             }
  148.         } else
  149.             switch ((int)(unsigned char)(*s++)) {
  150.             case ':':
  151.             colonmod = s - 1;
  152.             break;
  153.             case (int)STOUC(Hat):
  154.             case '^':
  155.             sense ^= 1;
  156.             break;
  157.             case '-':
  158.             sense ^= 2;
  159.             break;
  160. #ifdef S_IFLNK
  161.             case '@':
  162.             func = qualmode;
  163.             data = S_IFLNK;
  164.             break;
  165. #endif
  166. #ifdef S_IFSOCK
  167.             case (int)STOUC(Equals):
  168.             case '=':
  169.             func = qualmode;
  170.             data = S_IFSOCK;
  171.             break;
  172. #endif
  173. #ifdef S_IFIFO
  174.             case 'p':
  175.             func = qualmode;
  176.             data = S_IFIFO;
  177.             break;
  178. #endif
  179.             case '/':
  180.             func = qualmode;
  181.             data = S_IFDIR;
  182.             break;
  183.             case '.':
  184.             func = qualmode;
  185.             data = S_IFREG;
  186.             break;
  187.             case '%':
  188.             if (*s == 'b')
  189.                 s++, func = qualisblk;
  190.             else if (*s == 'c')
  191.                 s++, func = qualischar;
  192.             else
  193.                 func = qualisdev;
  194.             break;
  195.             case (int)STOUC(Star):
  196.             func = qualiscom;
  197.             break;
  198.             case 'R':
  199.             func = qualflags;
  200.             data = 0004;
  201.             break;
  202.             case 'W':
  203.             func = qualflags;
  204.             data = 0002;
  205.             break;
  206.             case 'X':
  207.             func = qualflags;
  208.             data = 0001;
  209.             break;
  210.             case 'r':
  211.             func = qualflags;
  212.             data = 0400;
  213.             break;
  214.             case 'w':
  215.             func = qualflags;
  216.             data = 0200;
  217.             break;
  218.             case 'x':
  219.             func = qualflags;
  220.             data = 0100;
  221.             break;
  222.             case 's':
  223.             func = qualflags;
  224.             data = 04000;
  225.             break;
  226.             case 'S':
  227.             func = qualflags;
  228.             data = 02000;
  229.             break;
  230.             case 'd':
  231.             func = qualdev;
  232.             data = qgetnum(&s);
  233.             break;
  234.             case 'l':
  235.             func = qualnlink;
  236.             amc = -1;
  237.             goto getrange;
  238.             case 'U':
  239.             func = qualuid;
  240.             data = geteuid();
  241.             break;
  242.             case 'G':
  243.             func = qualgid;
  244.             data = getegid();
  245.             break;
  246.             case 'u':
  247.             func = qualuid;
  248.             if (idigit(*s))
  249.                 data = qgetnum(&s);
  250.             else {
  251.                 struct passwd *pw;
  252.                 char sav, *tt;
  253.  
  254.                 tt = get_strarg(s);
  255.                 if (!*tt) {
  256.                 zerr("missing end of name",
  257.                      NULL, 0);
  258.                 data = 0;
  259.                 } else {
  260.                 sav = *tt;
  261.                 *tt = '\0';
  262.  
  263.                 if ((pw = getpwnam(s + 1)))
  264.                     data = pw->pw_uid;
  265.                 else {
  266.                     zerr("unknown user", NULL, 0);
  267.                     data = 0;
  268.                 }
  269.                 if ((*tt = sav) != Outpar)
  270.                     s = tt + 1;
  271.                 else
  272.                     s = tt;
  273.                 }
  274.             }
  275.             break;
  276.             case 'g':
  277.             func = qualgid;
  278.             if (idigit(*s))
  279.                 data = qgetnum(&s);
  280.             else {
  281.                 struct group *gr;
  282.                 char sav, *tt;
  283.  
  284.                 tt = get_strarg(s);
  285.                 if (!*tt) {
  286.                 zerr("missing end of name",
  287.                      NULL, 0);
  288.                 data = 0;
  289.                 } else {
  290.                 sav = *tt;
  291.                 *tt = '\0';
  292.  
  293.                 if ((gr = getgrnam(s + 1)))
  294.                     data = gr->gr_gid;
  295.                 else {
  296.                     zerr("unknown group", NULL, 0);
  297.                     data = 0;
  298.                 }
  299.                 if ((*tt = sav) != Outpar)
  300.                     s = tt + 1;
  301.                 else
  302.                     s = tt;
  303.                 }
  304.             }
  305.             break;
  306.             case 'o':
  307.             func = qualeqflags;
  308.             data = qgetoctnum(&s);
  309.             break;
  310.             case 'M':
  311.             gf_markdirs = !(sense & 1);
  312.             break;
  313.             case 'T':
  314.             gf_listtypes = !(sense & 1);
  315.             break;
  316.             case 'N':
  317.             gf_nullglob = !(sense & 1);
  318.             break;
  319.             case 'D':
  320.             gf_noglobdots = sense & 1;
  321.             break;
  322.             case 'a':
  323.             amc = 0;
  324.             func = qualtime;
  325.             goto getrange;
  326.             case 'm':
  327.             amc = 1;
  328.             func = qualtime;
  329.             goto getrange;
  330.             case 'c':
  331.             amc = 2;
  332.             func = qualtime;
  333.             goto getrange;
  334.             case 'L':
  335.             func = qualsize;
  336.             amc = -1;
  337.               getrange:
  338.             timef = TT_DAYS;
  339.             if (amc >= 0)
  340.                 if (*s == 'h')
  341.                 timef = TT_HOURS, ++s;
  342.                 else if (*s == 'm')
  343.                 timef = TT_MINS, ++s;
  344.                 else if (*s == 'w')
  345.                 timef = TT_WEEKS, ++s;
  346.                 else if (*s == 'M')
  347.                 timef = TT_MONTHS, ++s;
  348.             if ((range = *s == '+' ? 1 : *s == '-' ? -1 : 0))
  349.                 ++s;
  350.             data = qgetnum(&s);
  351.             break;
  352.  
  353.             default:
  354.             zerr("unknown file attribute", NULL, 0);
  355.             return;
  356.             }
  357.         if (func) {
  358.             if (!qn)
  359.             qn = (struct qual *) hcalloc(sizeof *qn);
  360.             if (ql)
  361.             ql->next = qn;
  362.             ql = qn;
  363.             if (!quals)
  364.             quals = qo = qn;
  365.             qn->func = func;
  366.             qn->sense = sense;
  367.             qn->data = data;
  368.             qn->range = range;
  369.             qn->timef = timef;
  370.             qn->amc = amc;
  371.             qn = NULL;
  372.             qualct++;
  373.         }
  374.         if (errflag)
  375.             return;
  376.         }
  377.     }
  378.     } else if ((str[sl - 1] == '/') && 
  379.            !((str[sl - 2] == Star) &&
  380.          (str[sl - 3] == Star))) {    /* foo/ == foo(/) */
  381.     str[sl - 1] = '\0';
  382.     quals = (struct qual *) hcalloc(sizeof *quals);
  383.     quals->func = qualmode;
  384.     quals->data = S_IFDIR;
  385.     quals->sense = 0;
  386.     qualct = 1;
  387.     }
  388.  
  389.     if (*str == '/') {        /* pattern has absolute path */
  390.     str++;
  391.     pathbuf[0] = '/';
  392.     pathbuf[pathpos = 1] = '\0';
  393.     } else            /* pattern is relative to pwd */
  394.     pathbuf[pathpos = 0] = '\0';
  395.     q = parsepat(str);
  396.     if (!q || errflag) {    /* if parsing failed */
  397.     if (isset(NOBADPATTERN)) {
  398.         insnode(list, node, ostr);
  399.         return;
  400.     }
  401.     errflag = 0;
  402.     zerr("bad pattern: %s", ostr, 0);
  403.     return;
  404.     }
  405.     matchptr = matchbuf = (char **)zalloc((matchsz = 16) * sizeof(char *));
  406.  
  407.     matchct = 0;
  408.     scanner(q);            /* do the globbing */
  409.     if (matchct)
  410.     badcshglob |= 2;
  411.     else if (!gf_nullglob)
  412.     if (isset(CSHNULLGLOB)) {
  413.         badcshglob |= 1;
  414.     } else if (unset(NONOMATCH)) {
  415.         zerr("no matches found: %s", ostr, 0);
  416.         free(matchbuf);
  417.         return;
  418.     } else {
  419.         *matchptr++ = dupstring(ostr);
  420.         matchct = 1;
  421.     }
  422.     qsort((vptr) & matchbuf[0], matchct, sizeof(char *),
  423.            (int (*)DCLPROTO((const void *, const void *)))notstrcmp);
  424.  
  425.     matchptr = matchbuf;
  426.     while (matchct--)        /* insert matches in the arg list */
  427.     insnode(list, node, *matchptr++);
  428.     free(matchbuf);
  429.     *np = (next) ? prevnode(next) : lastnode(list);
  430. }
  431.  
  432. /* get number after qualifier */
  433.  
  434. long qgetnum(s)            /**/
  435. char **s;
  436. {
  437.     long v = 0;
  438.  
  439.     if (!idigit(**s)) {
  440.     zerr("number expected", NULL, 0);
  441.     return 0;
  442.     }
  443.     while (idigit(**s))
  444.     v = v * 10 + *(*s)++ - '0';
  445.     return v;
  446. }
  447.  
  448. /* get octal number after qualifier */
  449.  
  450. long qgetoctnum(s)        /**/
  451. char **s;
  452. {
  453.     long v = 0;
  454.  
  455.     if (!idigit(**s)) {
  456.     zerr("octal number expected", NULL, 0);
  457.     return 0;
  458.     }
  459.     while (**s >= '0' && **s <= '7')
  460.     v = v * 010 + *(*s)++ - '0';
  461.     return v;
  462. }
  463.  
  464. int notstrcmp(a, b)        /**/
  465. char **a;
  466. char **b;
  467. {
  468.     char *c = *b, *d = *a;
  469.     int x1, x2, cmp;
  470.  
  471.     for (; *c == *d && *c; c++, d++);
  472.     cmp = (int)(unsigned char)*c - (int)(unsigned char)*d;
  473.     if (isset(NUMERICGLOBSORT)) {
  474.     for (; c > *b && idigit(c[-1]); c--, d--);
  475.     if (idigit(*c) && idigit(*d)) {
  476.         x1 = atoi(c);
  477.         x2 = atoi(d);
  478.         if (x1 != x2)
  479.         return x1 - x2;
  480.     }
  481.     }
  482.     return cmp;
  483. }
  484.  
  485. int forstrcmp(a, b)        /**/
  486. char **a;
  487. char **b;
  488. {
  489.     char *c = *b, *d = *a;
  490.  
  491.     for (; *c == *d && *c; c++, d++);
  492.     return ((int)(unsigned char)*d - (int)(unsigned char)*c);
  493. }
  494.  
  495. /* add a match to the list */
  496.  
  497. void insert(s)            /**/
  498. char *s;
  499. {
  500.     struct stat buf, buf2, *bp;
  501.     int statted = 0;
  502.  
  503.     if (exclude && domatch(s, exclude, gf_noglobdots))
  504.     return;
  505.     if (gf_listtypes || gf_markdirs) {
  506.     statted = 1;
  507.     if (!lstat(s, &buf) && (gf_listtypes || S_ISDIR(buf.st_mode))) {
  508.         char *t;
  509.         int ll = strlen(s);
  510.  
  511.         t = (char *)ncalloc(ll + 2);
  512.         strcpy(t, s);
  513.         t[ll] = file_type(buf.st_mode);
  514.         t[ll + 1] = '\0';
  515.         s = t;
  516.     }
  517.     }
  518.     if (qualct || qualorct) {    /* do the (X) (^X) stuff */
  519.     struct qual *qo, *qn;
  520.     int t = 0;
  521.  
  522.     if (statted || lstat(s, &buf) >= 0) {
  523.         statted = 0;
  524.         for (qo = quals; qo && !t; qo = qo->or) {
  525.  
  526.         t = 1;
  527.         for (qn = qo; t && qn && qn->func; qn = qn->next) {
  528.             range = qn->range;
  529.             amc = qn->amc;
  530.             timef = qn->timef;
  531.             if ((qn->sense & 2) && !statted) {
  532.             statted = 1;
  533.             stat(s, &buf2);
  534.             }
  535.             bp = (qn->sense & 2) ? &buf2 : &buf;
  536.             if (!(!!((qn->func) (bp, qn->data)) ^
  537.               (qn->sense & 1))) {
  538.             t = 0;
  539.             break;
  540.             }
  541.         }
  542.         }
  543.     }
  544.     if (!t)
  545.         return;
  546.     }
  547.     if (colonmod) {
  548.     char *cm2 = colonmod;
  549.  
  550.     modify(&s, &cm2);
  551.     }
  552.     *matchptr++ = s;
  553.     if (++matchct == matchsz) {
  554.     matchbuf = (char **)realloc((char *)matchbuf,
  555.                     sizeof(char **) * (matchsz *= 2));
  556.  
  557.     matchptr = matchbuf + matchct;
  558.     }
  559. }
  560.  
  561. #ifdef __STDC__
  562. char file_type(mode_t filemode)
  563. {
  564. #else
  565. char file_type(filemode)    /**/
  566. mode_t filemode;
  567. {
  568. #endif
  569.     switch (filemode & S_IFMT) {    /* screw POSIX */
  570.       case S_IFDIR:
  571.     return '/';
  572. #ifdef S_IFIFO
  573.       case S_IFIFO:
  574.     return '|';
  575. #endif
  576.       case S_IFCHR:
  577.     return '%';
  578.       case S_IFBLK:
  579.     return '#';
  580. #ifdef S_IFLNK
  581.       case S_IFLNK:
  582.     return /* (access(pbuf, F_OK) == -1) ? '&' :*/ '@';
  583. #endif
  584. #ifdef S_IFSOCK
  585.       case S_IFSOCK:
  586.     return '=';
  587. #endif
  588.       default:
  589.     if (filemode & 0111)
  590.         return '*';
  591.     else
  592.         return ' ';
  593.     }
  594. }
  595.  
  596. /* check to see if str is eligible for filename generation */
  597.  
  598. int haswilds(str)        /**/
  599. char *str;
  600. {
  601.     if ((*str == Inbrack || *str == Outbrack) && !str[1])
  602.     return 0;
  603.     if (str[0] == '%')
  604.     return 0;
  605.     for (; *str; str++)
  606.     if (*str == Pound || *str == Hat || *str == Star ||
  607.         *str == Bar || *str == Inbrack || *str == Inang ||
  608.         *str == Quest || (*str == Inpar && str[1] == ':'))
  609.         return 1;
  610.     return 0;
  611. }
  612.  
  613. /* check to see if str is eligible for brace expansion */
  614.  
  615. int hasbraces(str)        /**/
  616. char *str;
  617. {
  618.     int mb, bc, cmct1, cmct2;
  619.     char *lbr = NULL;
  620.  
  621.     if (str[0] == Inbrace && str[1] == Outbrace)
  622.     return 0;
  623.     if (isset(BRACECCL)) {
  624.     for (mb = bc = 0; *str; ++str)
  625.         if (*str == Inbrace) {
  626.         if (++bc > mb)
  627.             mb = bc;
  628.         } else if (*str == Outbrace)
  629.         if (--bc < 0)
  630.             return (0);
  631.     return (mb && bc == 0);
  632.     }
  633.     for (mb = bc = cmct1 = cmct2 = 0; *str; str++) {
  634.     if (*str == Inbrace) {
  635.         if (!bc)
  636.         lbr = str;
  637.         bc++;
  638.         if (str[4] == Outbrace && str[2] == '-') {    /* {a-z} */
  639.         cmct1++;
  640.         if (bc == 1)
  641.             cmct2++;
  642.         }
  643.     } else if (*str == Outbrace) {
  644.         bc--;
  645.         if (!bc) {
  646.         if (!cmct2) {
  647.             *lbr = '{';
  648.             *str = '}';
  649.         }
  650.         cmct2 = 0;
  651.         }
  652.     } else if (*str == Comma && bc) {
  653.         cmct1++;
  654.         if (bc == 1)
  655.         cmct2++;
  656.     }
  657.     if (bc > mb)
  658.         mb = bc;
  659.     if (bc < 0)
  660.         return 0;
  661.     }
  662.     return (mb && bc == 0 && cmct1);
  663. }
  664.  
  665. /* expand stuff like >>*.c */
  666.  
  667. int xpandredir(fn, tab)        /**/
  668. struct redir *fn;
  669. Lklist tab;
  670. {
  671.     Lklist fake;
  672.     char *nam;
  673.     struct redir *ff;
  674.     int ret = 0;
  675.  
  676.     fake = newlist();
  677.     addnode(fake, fn->name);
  678.     prefork(fake, 0);
  679.     if (!errflag)
  680.     postfork(fake, 1);
  681.     if (errflag)
  682.     return 0;
  683.     if (full(fake) && !nextnode(firstnode(fake))) {
  684.     fn->name = (char *)peekfirst(fake);
  685.     untokenize(fn->name);
  686.     } else
  687.     while ((nam = (char *)ugetnode(fake))) {
  688.         ff = (struct redir *)alloc(sizeof *ff);
  689.         *ff = *fn;
  690.         ff->name = nam;
  691.         addnode(tab, ff);
  692.         ret = 1;
  693.     }
  694.     return ret;
  695. }
  696.  
  697. /* concatenate s1 and s2 in dynamically allocated buffer */
  698.  
  699. char *dyncat(s1, s2)        /**/
  700. char *s1;
  701. char *s2;
  702. {
  703.     char *ptr;
  704.  
  705.     ptr = (char *)ncalloc(strlen(s1) + strlen(s2) + 1);
  706.     strcpy(ptr, s1);
  707.     strcat(ptr, s2);
  708.     return ptr;
  709. }
  710.  
  711. /* concatenate s1, s2, and s3 in dynamically allocated buffer */
  712.  
  713. char *tricat(s1, s2, s3)    /**/
  714. char *s1;
  715. char *s2;
  716. char *s3;
  717. {
  718.     char *ptr;
  719.  
  720.     ptr = (char *)zalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
  721.     strcpy(ptr, s1);
  722.     strcat(ptr, s2);
  723.     strcat(ptr, s3);
  724.     return ptr;
  725. }
  726.  
  727. /* brace expansion */
  728.  
  729. void xpandbraces(list, np)    /**/
  730. Lklist list;
  731. Lknode *np;
  732. {
  733.     Lknode node = (*np), last = prevnode(node);
  734.     char *str = (char *)getdata(node), *str3 = str, *str2;
  735.     int prev, bc, comma;
  736.  
  737.     for (; *str != Inbrace; str++);
  738.     for (str2 = str, bc = comma = 0; *str2; ++str2)
  739.     if (*str2 == Inbrace)
  740.         ++bc;
  741.     else if (*str2 == Outbrace) {
  742.         if (--bc == 0)
  743.         break;
  744.     } else if (bc == 1 && *str2 == Comma)
  745.         ++comma;
  746.     if (!comma && !bc && isset(BRACECCL)) {    /* {a-mnop} */
  747.     char ccl[256], *p;
  748.     unsigned char c1, c2, lastch;
  749.  
  750.     uremnode(list, node);
  751.     memset(ccl, 0, sizeof(ccl) / sizeof(ccl[0]));
  752.     for (p = str + 1, lastch = 0; p < str2;) {
  753.         if (itok(c1 = *p++))
  754.         c1 = ztokens[c1 - STOUC(Pound)];
  755.         if (itok(c2 = *p))
  756.         c2 = ztokens[c2 - STOUC(Pound)];
  757.         if (c1 == '-' && lastch && p < str2 && (int) lastch <= (int) c2) {
  758.         while ((int) lastch < (int) c2)
  759.             ccl[lastch++] = 1;
  760.         lastch = 0;
  761.         } else
  762.         ccl[lastch = c1] = 1;
  763.     }
  764.     strcpy(str + 1, str2 + 1);
  765.     for (p = ccl + 255; p-- > ccl;)
  766.         if (*p) {
  767.         *str = p - ccl;
  768.         insnode(list, last, dupstring(str3));
  769.         }
  770.     *np = nextnode(last);
  771.     return;
  772.     }
  773.     if (str[2] == '-' && str[4] == Outbrace) {    /* {a-z} */
  774.     char c1, c2;
  775.  
  776.     uremnode(list, node);
  777.     chuck(str);
  778.     c1 = *str;
  779.     chuck(str);
  780.     chuck(str);
  781.     c2 = *str;
  782.     chuck(str);
  783.     if (itok(c1))
  784.         c1 = ztokens[c1 - Pound];
  785.     if (itok(c2))
  786.         c2 = ztokens[c2 - Pound];
  787.     if (c1 < c2)
  788.         for (; c2 >= c1; c2--) {    /* {a-z} */
  789.         *str = c2;
  790.         insnode(list, last, dupstring(str3));
  791.     } else
  792.         for (; c2 <= c1; c2++) {    /* {z-a} */
  793.         *str = c2;
  794.         insnode(list, last, dupstring(str3));
  795.         }
  796.     *np = nextnode(last);
  797.     return;
  798.     }
  799.     prev = str - str3;
  800.     str2 = getparen(str++);
  801.     if (!str2) {
  802.     zerr("how did you get this error?", NULL, 0);
  803.     return;
  804.     }
  805.     uremnode(list, node);
  806.     node = last;
  807.     for (;;) {
  808.     char *zz, *str4;
  809.     int cnt;
  810.  
  811.     for (str4 = str, cnt = 0; cnt || (*str != Comma && *str !=
  812.                       Outbrace); str++)
  813.         if (*str == Inbrace)
  814.         cnt++;
  815.         else if (*str == Outbrace)
  816.         cnt--;
  817.         else if (!*str)
  818.         exit(10);
  819.     zz = (char *)zalloc(prev + (str - str4) + strlen(str2) + 1);
  820.     ztrncpy(zz, str3, prev);
  821.     strncat(zz, str4, str - str4);
  822.     strcat(zz, str2);
  823.     insnode(list, node, zz);
  824.     incnode(node);
  825.     if (*str != Outbrace)
  826.         str++;
  827.     else
  828.         break;
  829.     }
  830.     *np = nextnode(last);
  831. }
  832.  
  833. /* get closing paren, given pointer to opening paren */
  834.  
  835. char *getparen(str)        /**/
  836. char *str;
  837. {
  838.     int cnt = 1;
  839.     char typein = *str++, typeout = typein + 1;
  840.  
  841.     for (; *str && cnt; str++)
  842.     if (*str == typein)
  843.         cnt++;
  844.     else if (*str == typeout)
  845.         cnt--;
  846.     if (!str && cnt)
  847.     return NULL;
  848.     return str;
  849. }
  850.  
  851. /* check to see if a matches b (b is not a filename pattern) */
  852.  
  853. int matchpat(a, b)        /**/
  854. char *a;
  855. char *b;
  856. {
  857.     Comp c;
  858.     int val, len;
  859.     char *b2;
  860.  
  861.     remnulargs(b);
  862.     len = strlen(b);
  863.     b2 = (char *)alloc(len + 3);
  864.     strcpy(b2 + 1, b);
  865.     b2[0] = Inpar;
  866.     b2[len + 1] = Outpar;
  867.     b2[len + 2] = '\0';
  868.     c = parsereg(b2);
  869.     if (!c) {
  870.     zerr("bad pattern: %s", b, 0);
  871.     return 0;
  872.     }
  873.     val = domatch(a, c, 0);
  874.     return val;
  875. }
  876.  
  877. /* do the ${foo%%bar}, ${foo#bar} stuff */
  878. /* please do not laugh at this code. */
  879.  
  880. char *get_match_ret(s, b, e, fl)    /**/
  881. char *s;
  882. int b;
  883. int e;
  884. int fl;
  885. {
  886.     char buf[80], *r, *p, *rr;
  887.     int ll = 0, l = strlen(s), bl = 0, t = 0, i;
  888.  
  889.     if (fl & 8)
  890.     ll += 1 + (e - b);
  891.     if (fl & 16)
  892.     ll += 1 + (l - (e - b));
  893.     if (fl & 32) {
  894.     sprintf(buf, "%d ", b + 1);
  895.     ll += (bl = strlen(buf));
  896.     }
  897.     if (fl & 64) {
  898.     sprintf(buf + bl, "%d ", e + 1);
  899.     ll += (bl = strlen(buf));
  900.     }
  901.     if (fl & 128) {
  902.     sprintf(buf + bl, "%d ", e - b);
  903.     ll += (bl = strlen(buf));
  904.     }
  905.     if (bl)
  906.     buf[bl - 1] = '\0';
  907.  
  908.     rr = r = (char *)ncalloc(ll);
  909.  
  910.     if (fl & 8) {
  911.     for (i = b, p = s + b; i < e; i++)
  912.         *rr++ = *p++;
  913.     t = 1;
  914.     }
  915.     if (fl & 16) {
  916.     if (t)
  917.         *rr++ = ' ';
  918.     for (i = 0, p = s; i < b; i++)
  919.         *rr++ = *p++;
  920.     for (i = e, p = s + e; i < l; i++)
  921.         *rr++ = *p++;
  922.     t = 1;
  923.     }
  924.     *rr = '\0';
  925.     if (bl) {
  926.     if (t)
  927.         *rr++ = ' ';
  928.     strcpy(rr, buf);
  929.     }
  930.     return r;
  931. }
  932.  
  933. void getmatch(sp, pat, fl, n)    /**/
  934. char **sp;
  935. char *pat;
  936. int fl;
  937. int n;
  938. {
  939.     Comp c;
  940.     char *s = *sp, *t, sav;
  941.     int i, j, l = strlen(*sp);
  942.  
  943.     remnulargs(pat);
  944.     c = parsereg(pat);
  945.     if (!c) {
  946.     zerr("bad pattern: %s", pat, 0);
  947.     return;
  948.     }
  949.     switch (fl & 7) {
  950.     case 0:
  951.     for (i = 1, t = s + 1; i <= l; i++, t++) {
  952.         sav = *t;
  953.         *t = '\0';
  954.         if (domatch(s, c, 0) && !--n) {
  955.         *t = sav;
  956.         *sp = get_match_ret(*sp, 0, i, fl);
  957.         return;
  958.         }
  959.         *t = sav;
  960.     }
  961.     break;
  962.  
  963.     case 1:
  964.     for (t = s + l - 1; t >= s; t--) {
  965.         if (domatch(t, c, 0) && !--n) {
  966.         *sp = get_match_ret(*sp, t - s, l, fl);
  967.         return;
  968.         }
  969.     }
  970.     break;
  971.  
  972.     case 2:
  973.     for (t = s + l; t > s; t--) {
  974.         sav = *t;
  975.         *t = '\0';
  976.         if (domatch(s, c, 0) && !--n) {
  977.         *t = sav;
  978.         *sp = get_match_ret(*sp, 0, t - s, fl);
  979.         return;
  980.         }
  981.         *t = sav;
  982.     }
  983.     break;
  984.  
  985.     case 3:
  986.     for (i = 0, t = s; i < l; i++, t++) {
  987.         if (domatch(t, c, 0) && !--n) {
  988.         *sp = get_match_ret(*sp, i, l, fl);
  989.         return;
  990.         }
  991.     }
  992.     break;
  993.  
  994.     case 4:
  995.     for (i = 1; i <= l; i++) {
  996.         for (t = s + i, j = i; j <= l; j++, t++) {
  997.         sav = *t;
  998.         *t = '\0';
  999.         if (domatch(s + i - 1, c, 0) && !--n) {
  1000.             *t = sav;
  1001.             *sp = get_match_ret(*sp, i - 1, j, fl);
  1002.             return;
  1003.         }
  1004.         *t = sav;
  1005.         }
  1006.     }
  1007.     break;
  1008.  
  1009.     case 5:
  1010.     for (i = 1; i <= l; i++) {
  1011.         for (t = s + l, j = i; j <= l; j++, t--) {
  1012.         sav = *t;
  1013.         *t = '\0';
  1014.         if (domatch(t - i, c, 0) && !--n) {
  1015.             *t = sav;
  1016.             *sp = get_match_ret(*sp, l - j, t - s, fl);
  1017.             return;
  1018.         }
  1019.         *t = sav;
  1020.         }
  1021.     }
  1022.     break;
  1023.  
  1024.     case 6:
  1025.     for (i = l; i; i--) {
  1026.         for (t = s, j = i; j <= l; j++, t++) {
  1027.         sav = t[i];
  1028.         t[i] = '\0';
  1029.         if (domatch(t, c, 0) && !--n) {
  1030.             t[i] = sav;
  1031.             *sp = get_match_ret(*sp, t - s, t - s + i, fl);
  1032.             return;
  1033.         }
  1034.         t[i] = sav;
  1035.         }
  1036.     }
  1037.     break;
  1038.  
  1039.     case 7:
  1040.     for (i = l; i; i--) {
  1041.         for (t = s + l, j = i; j <= l; j++, t--) {
  1042.         sav = *t;
  1043.         *t = '\0';
  1044.         if (domatch(t - i, c, 0) && !--n) {
  1045.             *t = sav;
  1046.             *sp = get_match_ret(*sp, l - j, t - s, fl);
  1047.             return;
  1048.         }
  1049.         *t = sav;
  1050.         }
  1051.     }
  1052.     break;
  1053.     }
  1054.     *sp = get_match_ret(*sp, 0, 0, fl);
  1055. }
  1056.  
  1057. /* add a component to pathbuf */
  1058.  
  1059. SPROTO(int addpath, (char * s));
  1060.  
  1061. static int addpath(s)
  1062. char *s;
  1063. {
  1064.     if ((int) strlen(s) + pathpos >= MAXPATHLEN)
  1065.     return 0;
  1066.     while ((pathbuf[pathpos++] = *s++));
  1067.     pathbuf[pathpos - 1] = '/';
  1068.     pathbuf[pathpos] = '\0';
  1069.     return 1;
  1070. }
  1071.  
  1072. char *getfullpath(s)        /**/
  1073. char *s;
  1074. {
  1075.     static char buf[MAXPATHLEN];
  1076.  
  1077.     strcpy(buf, pathbuf);
  1078.     strcat(buf, s);
  1079.     return buf;
  1080. }
  1081.  
  1082. /* do the globbing */
  1083.  
  1084. void scanner(q)            /**/
  1085. Complist q;
  1086. {
  1087.     Comp c;
  1088.     int closure;
  1089.  
  1090.     if (!q)
  1091.     return;
  1092.     if ((closure = q->closure))    /* (foo/)# */
  1093.     if (q->closure == 2)    /* (foo/)## */
  1094.         q->closure = 1;
  1095.     else
  1096.         scanner(q->next);
  1097.     if ((c = q->comp)) {
  1098.     if (!(c->next || c->left) && !haswilds(c->str))
  1099.         if (q->next) {
  1100.         int oppos = pathpos;
  1101.  
  1102.         if (errflag)
  1103.             return;
  1104.         if (q->closure && !strcmp(c->str, "."))
  1105.             return;
  1106.         if (!addpath(c->str))
  1107.             return;
  1108.         if (!closure || exists(pathbuf))
  1109.             scanner((q->closure) ? q : q->next);
  1110.         pathbuf[pathpos = oppos] = '\0';
  1111.         } else {
  1112.         char *s;
  1113.  
  1114.         if (exists(s = getfullpath(c->str)))
  1115.             insert(dupstring(s));
  1116.     } else {
  1117.         char *fn;
  1118.         int dirs = !!q->next;
  1119.         struct dirent *de;
  1120.         DIR *lock = opendir((*pathbuf) ? pathbuf : ".");
  1121.  
  1122.         if (lock == NULL)
  1123.         return;
  1124.         while ((de = readdir(lock))) {
  1125.         if (errflag)
  1126.             break;
  1127.         fn = &de->d_name[0];
  1128.         if (fn[0] == '.'
  1129.             && (fn[1] == '\0'
  1130.             || (fn[1] == '.' && fn[2] == '\0')))
  1131.             continue;
  1132.         if (!dirs && !colonmod &&
  1133.             ((glob_pre && !strpfx(glob_pre, fn))
  1134.              || (glob_suf && !strsfx(glob_suf, fn))))
  1135.             continue;
  1136.         if (domatch(fn, c, gf_noglobdots)) {
  1137.             int oppos = pathpos;
  1138.  
  1139.             if (dirs) {
  1140.             if (closure) {
  1141.                 int type3;
  1142.                 struct stat buf;
  1143.  
  1144.                 if (lstat(getfullpath(fn), &buf) == -1) {
  1145.                 if (errno != ENOENT && errno != EINTR &&
  1146.                     errno != ENOTDIR) {
  1147.                     zerr("%e: %s", fn, errno);
  1148.                     errflag = 0;
  1149.                 }
  1150.                 continue;
  1151.                 }
  1152.                 type3 = buf.st_mode & S_IFMT;
  1153.                 if (type3 != S_IFDIR)
  1154.                 continue;
  1155.             }
  1156.             if (addpath(fn))
  1157.                 scanner((q->closure) ? q : q->next);    /* scan next level */
  1158.             pathbuf[pathpos = oppos] = '\0';
  1159.             } else
  1160.             insert(dyncat(pathbuf, fn));
  1161.         }
  1162.         }
  1163.         closedir(lock);
  1164.     }
  1165.     } else
  1166.     zerr("no idea how you got this error message.", NULL, 0);
  1167. }
  1168.  
  1169. /* do the [..(foo)..] business */
  1170.  
  1171. int minimatch(pat, str)        /**/
  1172. char **pat;
  1173. char **str;
  1174. {
  1175.     char *pt = *pat + 1, *s = *str;
  1176.  
  1177.     for (; *pt != Outpar; s++, pt++)
  1178.     if ((*pt != Quest || !*s) && *pt != *s) {
  1179.         *pat = getparen(*pat) - 1;
  1180.         return 0;
  1181.     }
  1182.     *str = s - 1;
  1183.     return 1;
  1184. }
  1185.  
  1186. static char *pptr;
  1187. static Comp tail = 0;
  1188. static int first;
  1189.  
  1190. int domatch(str, c, fist)    /**/
  1191. char *str;
  1192. Comp c;
  1193. int fist;
  1194. {
  1195.     pptr = str;
  1196.     first = fist;
  1197.     return doesmatch(c);
  1198. }
  1199.  
  1200. #define untok(C)  (itok(C) ? ztokens[(C) - Pound] : (C))
  1201.  
  1202.  
  1203. /* see if current pattern matches c */
  1204.  
  1205. int doesmatch(c)        /**/
  1206. Comp c;
  1207. {
  1208.     char *pat = c->str;
  1209.  
  1210.  tailrec:
  1211.     if (c->closure == 1) {
  1212.     char *saves = pptr;
  1213.  
  1214.     if (first && *pptr == '.')
  1215.         return 0;
  1216.     if (doesmatch(c->next))
  1217.         return 1;
  1218.     pptr = saves;
  1219.     first = 0;
  1220.     }
  1221.     for (;;) {
  1222.     if (!pat || !*pat) {
  1223.         char *saves;
  1224.         int savei;
  1225.  
  1226.         if (errflag)
  1227.         return 0;
  1228.         saves = pptr;
  1229.         savei = first;
  1230.         if (c->left || c->right)
  1231.         if (!doesmatch(c->left))
  1232.             if (c->right) {
  1233.             pptr = saves;
  1234.             first = savei;
  1235.             if (!doesmatch(c->right))
  1236.                 return 0;
  1237.             } else
  1238.             return 0;
  1239.         if (c->closure) {
  1240.         pat = c->str;
  1241.         goto tailrec;
  1242.         }
  1243.         if (!c->next)
  1244.         return (!c->last || !*pptr);
  1245.         c = c->next;
  1246.         pat = c->str;
  1247.         goto tailrec;
  1248.     }
  1249.     if (first && *pptr == '.' && *pat != '.')
  1250.         return 0;
  1251.     if (*pat == Star) {    /* final * is not expanded to ?#; returns success */
  1252.         while (*pptr)
  1253.         pptr++;
  1254.         return 1;
  1255.     }
  1256.     first = 0;
  1257.     if (*pat == Quest && *pptr) {
  1258.         pptr++;
  1259.         pat++;
  1260.         continue;
  1261.     }
  1262.     if (*pat == Hat)
  1263.         return 1 - doesmatch(c->next);
  1264.     if (*pat == Inbrack) {
  1265.         if (!*pptr)
  1266.         break;
  1267.         if (pat[1] == Hat || pat[1] == '^' || pat[1] == '!') {
  1268.         pat[1] = Hat;
  1269.         for (pat += 2; *pat != Outbrack && *pat; pat++)
  1270.             if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack) {
  1271.             if (untok(pat[-1]) <= *pptr && untok(pat[1]) >= *pptr)
  1272.                 break;
  1273.             } else if (*pptr == untok(*pat))
  1274.             break;
  1275.         if (!*pat) {
  1276.             zerr("something is very wrong.", NULL, 0);
  1277.             return 0;
  1278.         }
  1279.         if (*pat != Outbrack)
  1280.             break;
  1281.         pat++;
  1282.         pptr++;
  1283.         continue;
  1284.         } else {
  1285.         for (pat++; *pat != Outbrack && *pat; pat++)
  1286.             if (*pat == Inpar) {
  1287.             if (minimatch(&pat, &pptr))
  1288.                 break;
  1289.             } else if (*pat == '-' && pat[-1] != Inbrack &&
  1290.                    pat[1] != Outbrack) {
  1291.             if (untok(pat[-1]) <= *pptr && untok(pat[1]) >= *pptr)
  1292.                 break;
  1293.             } else if (*pptr == untok(*pat))
  1294.             break;
  1295.         if (!pat || !*pat) {
  1296.             zerr("oh dear.  that CAN'T be right.", NULL, 0);
  1297.             return 0;
  1298.         }
  1299.         if (*pat == Outbrack)
  1300.             break;
  1301.         for (pptr++; *pat != Outbrack; pat++);
  1302.         pat++;
  1303.         continue;
  1304.         }
  1305.     }
  1306.     if (*pat == Inang) {
  1307.         int t1, t2, t3;
  1308.         char *ptr;
  1309.  
  1310.         if (*++pat == Outang) {    /* handle <> case */
  1311.         (void)zstrtol(pptr, &ptr, 10);
  1312.         if (ptr == pptr)
  1313.             break;
  1314.         pptr = ptr;
  1315.         pat++;
  1316.         } else {
  1317.         t1 = zstrtol(pptr, &ptr, 10);
  1318.         if (ptr == pptr)
  1319.             break;
  1320.         pptr = ptr;
  1321.         t2 = zstrtol(pat, &ptr, 10);
  1322.         if (*ptr != '-')
  1323.             t3 = t2, pat = ptr;
  1324.         else
  1325.             t3 = zstrtol(ptr + 1, &pat, 10);
  1326.         if (!t3)
  1327.             t3 = -1;
  1328.         if (*pat++ != Outang)
  1329.             exit(21);
  1330.         if (t1 < t2 || (t3 != -1 && t1 > t3))
  1331.             break;
  1332.         }
  1333.         continue;
  1334.     }
  1335.     if (*pptr == *pat) {
  1336.         pptr++;
  1337.         pat++;
  1338.         continue;
  1339.     }
  1340.     break;
  1341.     }
  1342.     return 0;
  1343. }
  1344.  
  1345. Complist parsepat(str)        /**/
  1346. char *str;
  1347. {
  1348.     char *s;
  1349.  
  1350.     exclude = NULL;
  1351.     if (isset(EXTENDEDGLOB)) {
  1352.     s = str + strlen(str);
  1353.     while (s-- > str) {
  1354.         if (*s == Tilde && s[1]) {
  1355.         *s++ = '\0';
  1356.         exclude = parsereg(s);
  1357.         if (!exclude)
  1358.             return NULL;
  1359.         break;
  1360.         }
  1361.     }
  1362.     }
  1363.     mode = 0;
  1364.     pptr = str;
  1365.     return parsecomplist();
  1366. }
  1367.  
  1368. Comp parsereg(str)        /**/
  1369. char *str;
  1370. {
  1371.     mode = 1;
  1372.     pptr = str;
  1373.     return parsecompsw();
  1374. }
  1375.  
  1376. Complist parsecomplist()
  1377. {                /**/
  1378.     Comp c1;
  1379.     Complist p1;
  1380.  
  1381.     if (pptr[0] == Star && pptr[1] == Star &&
  1382.     (pptr[2] == '/' ||
  1383.      (pptr[2] == Star && pptr[3] == Star && pptr[4] == '/'))) {
  1384.     pptr += 3;
  1385.     if (pptr[-1] == Star)
  1386.         pptr += 2;
  1387.     p1 = (Complist) alloc(sizeof *p1);
  1388.     if ( (p1->next = parsecomplist()) == NULL ) {
  1389.         errflag = 1;
  1390.         return NULL;
  1391.     }
  1392.     p1->comp = (Comp) alloc(sizeof *p1->comp);
  1393.     p1->comp->last = 1;
  1394.     p1->comp->str = dupstring("*");
  1395.     *p1->comp->str = Star;
  1396.     p1->closure = 1;
  1397.     return p1;
  1398.     }
  1399.     if (*pptr == Inpar) {
  1400.     char *str;
  1401.     int pars = 1;
  1402.  
  1403.     for (str = pptr + 1; *str && pars; str++)
  1404.         if (*str == Inpar)
  1405.         pars++;
  1406.         else if (*str == Outpar)
  1407.         pars--;
  1408.     if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/')
  1409.         goto kludge;
  1410.     pptr++;
  1411.     if (!(c1 = parsecompsw()))
  1412.         return NULL;
  1413.     if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound) {
  1414.         int pdflag = 0;
  1415.  
  1416.         pptr += 3;
  1417.         if (*pptr == Pound) {
  1418.         pdflag = 1;
  1419.         pptr++;
  1420.         }
  1421.         p1 = (Complist) alloc(sizeof *p1);
  1422.         p1->comp = c1;
  1423.         p1->closure = 1 + pdflag;
  1424.         p1->next = parsecomplist();
  1425.         return (p1->comp) ? p1 : NULL;
  1426.     }
  1427.     } else {
  1428.       kludge:
  1429.     if (!(c1 = parsecompsw()))
  1430.         return NULL;
  1431.     if (*pptr == '/' || !*pptr) {
  1432.         int ef = *pptr == '/';
  1433.  
  1434.         p1 = (Complist) alloc(sizeof *p1);
  1435.         p1->comp = c1;
  1436.         p1->closure = 0;
  1437.         p1->next = (*pptr == '/') ? (pptr++, parsecomplist()) : NULL;
  1438.         return (ef && !p1->next) ? NULL : p1;
  1439.     }
  1440.     }
  1441.     errflag = 1;
  1442.     return NULL;
  1443. }
  1444.  
  1445. Comp parsecomp()
  1446. {                /**/
  1447.     Comp c = (Comp) alloc(sizeof *c), c1, c2;
  1448.     char *s = c->str = (char *)alloc(MAXPATHLEN * 2), *ls = NULL;
  1449.  
  1450.     c->next = tail;
  1451.  
  1452.     while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
  1453.        *pptr != Outpar) {
  1454.     if (*pptr == Hat) {
  1455.         *s++ = Hat;
  1456.         *s++ = '\0';
  1457.         pptr++;
  1458.         if (!(c->next = parsecomp()))
  1459.         return NULL;
  1460.         return c;
  1461.     }
  1462.     if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/')) {
  1463.         *s++ = '\0';
  1464.         pptr++;
  1465.         c1 = (Comp) alloc(sizeof *c1);
  1466.         *(c1->str = dupstring("?")) = Quest;
  1467.         c1->closure = 1;
  1468.         if (!(c2 = parsecomp()))
  1469.         return NULL;
  1470.         c1->next = c2;
  1471.         c->next = c1;
  1472.         return c;
  1473.     }
  1474.     if (*pptr == Inpar) {
  1475.         int pars = 1;
  1476.         char *startp = pptr, *endp;
  1477.         Comp stail = tail;
  1478.         int dpnd = 0;
  1479.  
  1480.         for (pptr = pptr + 1; *pptr && pars; pptr++)
  1481.         if (*pptr == Inpar)
  1482.             pars++;
  1483.         else if (*pptr == Outpar)
  1484.             pars--;
  1485.         if (pptr[-1] != Outpar) {
  1486.         errflag = 1;
  1487.         return NULL;
  1488.         }
  1489.         if (*pptr == Pound) {
  1490.         dpnd = 1;
  1491.         pptr++;
  1492.         if (*pptr == Pound) {
  1493.             pptr++;
  1494.             dpnd = 2;
  1495.         }
  1496.         }
  1497.         if (!(c1 = parsecomp()))
  1498.         return NULL;
  1499.         tail = c1;
  1500.         endp = pptr;
  1501.         pptr = startp;
  1502.         pptr++;
  1503.         *s++ = '\0';
  1504.         c->next = (Comp) alloc(sizeof *c);
  1505.         c->next->left = parsecompsw();
  1506.         c->next->closure = dpnd;
  1507.         c->next->next = (Comp) alloc(sizeof *c);
  1508.         pptr = endp;
  1509.         tail = stail;
  1510.         return c;
  1511.     }
  1512.     if (*pptr == Pound) {
  1513.         *s = '\0';
  1514.         pptr++;
  1515.         if (!ls)
  1516.         return NULL;
  1517.         if (*pptr == Pound) {
  1518.         pptr++;
  1519.         c->next = c1 = (Comp) alloc(sizeof *c);
  1520.         c1->str = dupstring(ls);
  1521.         } else
  1522.         c1 = c;
  1523.         c1->next = c2 = (Comp) alloc(sizeof *c);
  1524.         c2->str = dupstring(ls);
  1525.         c2->closure = 1;
  1526.         c2->next = parsecomp();
  1527.         if (!c2->next)
  1528.         return NULL;
  1529.         *ls++ = '\0';
  1530.         return c;
  1531.     }
  1532.     ls = s;
  1533.     if (*pptr == Inang) {
  1534.         int dshct;
  1535.  
  1536.         dshct = (pptr[1] == Outang);
  1537.         *s++ = *pptr++;
  1538.         while (*pptr && (*s++ = *pptr++) != Outang)
  1539.         if (s[-1] == '-')
  1540.             dshct++;
  1541.         else if (!idigit(s[-1]))
  1542.             break;
  1543.         if (s[-1] != Outang)
  1544.         return NULL;
  1545.     } else if (*pptr == Inbrack) {
  1546.         while (*pptr && (*s++ = *pptr++) != Outbrack);
  1547.         if (s[-1] != Outbrack)
  1548.         return NULL;
  1549.     } else if (itok(*pptr) && *pptr != Star && *pptr != Quest)
  1550.         *s++ = ztokens[*pptr++ - Pound];
  1551.     else
  1552.         *s++ = *pptr++;
  1553.     }
  1554.     if (*pptr == '/' || !*pptr)
  1555.     c->last = 1;
  1556.     *s++ = '\0';
  1557.     return c;
  1558. }
  1559.  
  1560. Comp parsecompsw()
  1561. {                /**/
  1562.     Comp c1, c2, c3;
  1563.  
  1564.     c1 = parsecomp();
  1565.     if (!c1)
  1566.     return NULL;
  1567.     if (*pptr == Bar) {
  1568.     c2 = (Comp) alloc(sizeof *c2);
  1569.     pptr++;
  1570.     c3 = parsecompsw();
  1571.     if (!c3)
  1572.         return NULL;
  1573.     c2->str = dupstring("");
  1574.     c2->left = c1;
  1575.     c2->right = c3;
  1576.     return c2;
  1577.     }
  1578.     return c1;
  1579. }
  1580.  
  1581. void tokenize(s)        /**/
  1582. char *s;
  1583. {
  1584.     char *t;
  1585.  
  1586.     for (; *s; s++)
  1587.     if (*s == '\\')
  1588.         chuck(s);
  1589.     else
  1590.         for (t = ztokens; *t; t++)
  1591.         if (*t == *s) {
  1592.             *s = (t - ztokens) + Pound;
  1593.             break;
  1594.         }
  1595. }
  1596.  
  1597. /* remove unnecessary Nulargs */
  1598.  
  1599. void remnulargs(s)        /**/
  1600. char *s;
  1601. {
  1602.     int nl = *s;
  1603.     char *t = s;
  1604.  
  1605.     while (*s)
  1606.     if (INULL(*s))
  1607.         chuck(s);
  1608.     else
  1609.         s++;
  1610.     if (!*t && nl) {
  1611.     t[0] = Nularg;
  1612.     t[1] = '\0';
  1613.     }
  1614. }
  1615.  
  1616. /* qualifier functions */
  1617.  
  1618. int qualdev(buf, dv)        /**/
  1619. struct stat *buf;
  1620. long dv;
  1621. {
  1622.     return buf->st_dev == dv;
  1623. }
  1624.  
  1625. int qualnlink(buf, ct)        /**/
  1626. struct stat *buf;
  1627. long ct;
  1628. {
  1629.     return (range < 0 ? buf->st_nlink < ct :
  1630.         range > 0 ? buf->st_nlink > ct :
  1631.         buf->st_nlink == ct);
  1632. }
  1633.  
  1634. int qualuid(buf, uid)        /**/
  1635. struct stat *buf;
  1636. long uid;
  1637. {
  1638.     return buf->st_uid == uid;
  1639. }
  1640.  
  1641. int qualgid(buf, gid)        /**/
  1642. struct stat *buf;
  1643. long gid;
  1644. {
  1645.     return buf->st_gid == gid;
  1646. }
  1647.  
  1648. int qualisdev(buf, junk)    /**/
  1649. struct stat *buf;
  1650. long junk;
  1651. {
  1652.     junk = buf->st_mode & S_IFMT;
  1653.     return junk == S_IFBLK || junk == S_IFCHR;
  1654. }
  1655.  
  1656. int qualisblk(buf, junk)    /**/
  1657. struct stat *buf;
  1658. long junk;
  1659. {
  1660.     junk = buf->st_mode & S_IFMT;
  1661.     return junk == S_IFBLK;
  1662. }
  1663.  
  1664. int qualischar(buf, junk)    /**/
  1665. struct stat *buf;
  1666. long junk;
  1667. {
  1668.     junk = buf->st_mode & S_IFMT;
  1669.     return junk == S_IFCHR;
  1670. }
  1671.  
  1672. int qualmode(buf, mod)        /**/
  1673. struct stat *buf;
  1674. long mod;
  1675. {
  1676.     return (buf->st_mode & S_IFMT) == mod;
  1677. }
  1678.  
  1679. int qualflags(buf, mod)        /**/
  1680. struct stat *buf;
  1681. long mod;
  1682. {
  1683.     return buf->st_mode & mod;
  1684. }
  1685.  
  1686. int qualeqflags(buf, mod)    /**/
  1687. struct stat *buf;
  1688. long mod;
  1689. {
  1690.     return (buf->st_mode & 07777) == mod;
  1691. }
  1692.  
  1693. int qualiscom(buf, mod)        /**/
  1694. struct stat *buf;
  1695. long mod;
  1696. {
  1697.     return (buf->st_mode & (S_IFMT | S_IEXEC)) == (S_IFREG | S_IEXEC);
  1698. }
  1699.  
  1700. int qualsize(buf, size)        /**/
  1701. struct stat *buf;
  1702. long size;
  1703. {
  1704.     return (range < 0 ? buf->st_size < size :
  1705.         range > 0 ? buf->st_size > size :
  1706.         buf->st_size == size);
  1707. }
  1708.  
  1709. int qualtime(buf, days)        /**/
  1710. struct stat *buf;
  1711. long days;
  1712. {
  1713.     time_t now, diff;
  1714.  
  1715.     time(&now);
  1716.     diff = now - (amc == 0 ? buf->st_atime : amc == 1 ? buf->st_mtime :
  1717.           buf->st_ctime);
  1718.     switch (timef) {
  1719.     case TT_DAYS:
  1720.     diff /= 86400l;
  1721.     break;
  1722.     case TT_HOURS:
  1723.     diff /= 3600l;
  1724.     break;
  1725.     case TT_MINS:
  1726.     diff /= 60l;
  1727.     break;
  1728.     case TT_WEEKS:
  1729.     diff /= 604800l;
  1730.     break;
  1731.     case TT_MONTHS:
  1732.     diff /= 2592000l;
  1733.     break;
  1734.     }
  1735.  
  1736.     return (range < 0 ? diff < days :
  1737.         range > 0 ? diff > days :
  1738.         diff == days);
  1739. }
  1740.